var config = require('../config/config');
var Sequelize = require('sequelize');
var uuid = require('node-uuid');

console.log('init sequelize');

var sequelize = new Sequelize(config.database, config.username, config.password, {
	host: config.host,
	dialect: 'mysql',
	pool: {
		max: 5,
		min: 0,
		idle: 10000
	}
});

function generateId() {
	return uuid.v4();
}

var ID_TYPE = Sequelize.STRING(50);
function defineModel(name, attributes) {
	var attrs = {};
	for (var key in attributes) {
		var value = attributes[key];
		if (typeof value === 'object' && value['type']) {
			value.allowNull = value.allowNull || false;
			attrs[key] = value;
		} else {
			attrs[key] = {
				type: value,
				allowNull: false
			};
		}
	}

	attrs.id = {
		type: ID_TYPE,
		primaryKey: true
	};
	attrs.createdAt = {
		type: Sequelize.BIGINT,
		allowNull: false
	};
	attrs.updatedAt = {
		type: Sequelize.BIGINT,
		allowNull: false
	};
	attrs.version = {
		type: Sequelize.BIGINT,
		allowNull: false
	};

	// console.log('model defined for table: ' + name + '\n' + JSON.stringify(attrs));
    console.log('model defined for table: ' + name + '\n' + JSON.stringify(attrs, function (k, v) {
        if (k === 'type') {
            for (let key in Sequelize) {
                if (key === 'ABSTRACT' || key === 'NUMBER') {
                    continue;
                }
                let dbType = Sequelize[key];
                if (typeof dbType === 'function') {
                    if (v instanceof dbType) {
                        if (v._length) {
                            return `${dbType.key}(${v._length})`;
                        }
                        return dbType.key;
                    }
                    if (v === dbType) {
                        return dbType.key;
                    }
                }
            }
        }
        return v;
    }, '  '));

	return sequelize.define(name, attrs, {
		tableName: name,
		timestamps: false,
		hooks: {
			beforeValidate: function(obj) {
				var now = Date.now();
				if (obj.isNewRecord) {
					console.log('will create entity...' + obj);
					if (!obj.id) {
						obj.id = generateId();
					}
					obj.createdAt = now;
					obj.updatedAt = now;
					obj.version = 0;
				} else {
					console.log('will update entity');
					obj.updateAt = Date.now();
					obj.version++;
				}
			}
		}
	});
}

var TYPES = ['STRING', 'INTEGER', 'BIGINT', 'TEXT', 'DOUBLE', 'DATEONLY', 'BOOLEAN'];
var exp = {
	defineModel: defineModel,
	sync: function() {
		// only allow create ddl in non-production environment
		if (process.env.NODE_ENV !== 'production') {
			return sequelize.sync({force: true});
		} else {
			throw new new Error('Cannot sync() when NODE_ENV is set to \'production\'.');
		}
	}
};

for (var i = 0; i < TYPES.length; i++) {
	var type = TYPES[i];
	exp[type] = Sequelize[type];
}

exp.ID = ID_TYPE;
exp.generateId = generateId;

module.exports = exp;